package timeDemo.beeboxesRule;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Ajie
 * @date 2022/11/14
 * @function
 */
public class MainTest {
    public static final int HOUR_TO_SECOND = 60 * 60;
    public static final int MINUTE_TO_SECOND = 60;

    public static void main(String[] args) {

    }

    public static int checkTimeRules(List<TimeRule> timeRules) {
        if (timeRules == null || timeRules.isEmpty()) return MatchCode.MATCH_FAIL_DEVICERULE;
        Date date = new Date(System.currentTimeMillis());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        // first to check deny TimeRule
        for (TimeRule timeRule : timeRules) {
            if (Action.ALLOW.equals(timeRule.getAction())) continue;
            // check days(cycle and timing days)
            if (TimeRule.Type.TIMING.equals(timeRule.getType())) {
                if (!checkInTimingDay(timeRule, calendar)) continue;
            }
            if (!checkDayType(timeRule, calendar)) continue;

            // check time
            if (checkInRangeTime(timeRule, calendar)) {
                return MatchCode.MATCH_FAIL_DEVICERULE;   //在拒绝通行的时间范围内
            }
        }

        // then to check allow rule
        for (TimeRule timeRule : timeRules) {
            if (Action.DENY.equals(timeRule.getAction())) continue;

            if (TimeRule.Type.TIMING.equals(timeRule.getType())) {
                if (!checkInTimingDay(timeRule, calendar)) continue;
            }
            if (!checkDayType(timeRule, calendar)) continue;

            if (checkInRangeTime(timeRule, calendar)) {
                return MatchCode.MATCH_SUCCESS_TIMERULE;
            }
        }

        // 新加逻辑   只要有允许的规则 且  当前时间没有通过就返回
        for (TimeRule timeRule : timeRules) {
            if (Action.DENY.equals(timeRule.getAction())) continue;
            return MatchCode.MATCH_FAIL_TIMERULE;
        }

        //既不在 拒绝通行的规则 也不在可允许通行的规则
        return MatchCode.MATCH_FAIL_DEVICERULE;
    }

    private static boolean checkInRangeTime(TimeRule timeRule, Calendar calendar) {
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        int nowTime = hour * HOUR_TO_SECOND + minute * MINUTE_TO_SECOND + second;
        // check time
        Range<Range.Time> timeRange = timeRule.getTimeRange();
        if (timeRange == null) return false;
        Range.Time start = timeRange.getStart();
        Range.Time end = timeRange.getEnd();
        int startTime = start.getHour() * HOUR_TO_SECOND + start.getMinute() * MINUTE_TO_SECOND + start.getSecond();
        int endTime = end.getHour() * HOUR_TO_SECOND + end.getMinute() * MINUTE_TO_SECOND + end.getSecond();

        return nowTime >= startTime && nowTime <= endTime;
    }

    private static boolean checkInTimingDay(TimeRule timeRule, Calendar calendar) {
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        String nowTime = convertTime(year, month, day);
        // dayRange and excludes
        Range<Range.Day> dayRange = timeRule.getDayRange();
        if (dayRange == null) return false;
        List<Range.Day> excludes = timeRule.getExcludes();

        Range.Day dayRangeStart = dayRange.getStart();
        Range.Day dayRangeEnd = dayRange.getEnd();
        String startTime = convertTime(dayRangeStart.getYear(), dayRangeStart.getMm(), dayRangeStart.getDay());
        String endTime = convertTime(dayRangeEnd.getYear(), dayRangeEnd.getMm(), dayRangeEnd.getDay());

        try {
            final DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());

            Date nowDate = dateFormat.parse(nowTime);
            Date startDate = dateFormat.parse(startTime);
            Date endDate = dateFormat.parse(endTime);

            if (nowDate.getTime() >= startDate.getTime()
                    && nowDate.getTime() <= endDate.getTime()) {
                Range<Range.Day> range = new Range<>();
                Range<Range.Day>.Day today = range.new Day();
                today.setYear(year);
                today.setDay(day);
                today.setMm(month);
                if (excludes == null || !excludes.contains(today)) return true;
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

        return false;
    }

    private static String convertTime(int year, int month, int day) {
        String yearString = String.valueOf(year);
        String monthString = String.valueOf(month);
        String dayString = String.valueOf(day);
        if (monthString.length() == 1) monthString = "0" + monthString;
        if (dayString.length() == 1) dayString = "0" + dayString;
        return yearString + monthString + dayString;
    }

    private static boolean checkDayType(TimeRule timeRule, Calendar calendar) {
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        TimeRule.DayType dayType = timeRule.getDayType();
        if (dayType == null) return false;
        switch (dayType) {
            case EVERYDAY:
                return true;
            case WEEKDAY:
                if (dayOfWeek == Calendar.SUNDAY || dayOfWeek == Calendar.SATURDAY)
                    return true;
                break;
            case CUSTOM:
                Set<Integer> customDays = timeRule.getCustomDays();
                if (customDays != null && customDays.contains(dayOfWeek)) return true;
                break;
        }
        return false;
    }

}


